/*
 * Most parts of this file is copied from the original edition.
 *     The page-related parts are obviously architecture-independent.
 * Should consider merging them into a common header in the future.
 */

#ifndef __ARCH_UM_INCLUDE_MEMLAYOUT_H__
#define __ARCH_UM_INCLUDE_MEMLAYOUT_H__

#include <mmu.h>

#define KERNTOP            (KERNBASE + KMEMSIZE)
#define UM_RESERVED_SIZE   0x400000
#define UM_RESERVED        (KERNTOP - UM_RESERVED_SIZE)
#define UM_STUB_CODE       0x100000
#define UM_STUB_DATA       (UM_STUB_CODE + PGSIZE)
#define UM_SHARED_MEM      (UM_STUB_DATA + PGSIZE)
#define UM_SHARED_MEM_END  (UM_SHARED_MEM + PGSIZE)
#define UM_SPACE_TOP       0xC0000000

#ifndef __ASSEMBLER__

#include <types.h>
#include <atomic.h>
#include <list.h>

/* Basic types for mm. */
typedef uintptr_t pte_t;
typedef uintptr_t pde_t;

/* Virtual physical memory addresses.
 * Instead of macros, they are defined as variables because they can be determined only at runtime.
 * Define those variables in pmm.c
 */
extern uintptr_t KERNBASE;
extern uintptr_t KMEMSIZE;
extern uintptr_t VPT;

/* *
 * struct Page - Page descriptor structures. Each Page describes one
 * physical page. In pmm.h, you can find lots of useful functions
 * that convert Page to other data types, such as phyical address.
 * */
struct Page {
    atomic_t ref;                   // page frame's reference counter
    uint32_t flags;                 // array of flags that describe the status of the page frame
    unsigned int property;          // used in buddy system, stores the order (the X in 2^X) of the continuous memory block
    int zone_num;                   // used in buddy system, the No. of zone which the page belongs to
    list_entry_t page_link;         // free list link
};

/* Flags describing the status of a page frame */
#define PG_reserved					0		// the page descriptor is reserved for kernel or unusable
#define PG_property					1		// the member 'property' is valid

#define SetPageReserved(page)		set_bit(PG_reserved, &((page)->flags))
#define ClearPageReserved(page)		clear_bit(PG_reserved, &((page)->flags))
#define PageReserved(page)			test_bit(PG_reserved, &((page)->flags))
#define SetPageProperty(page)		set_bit(PG_property, &((page)->flags))
#define ClearPageProperty(page)		clear_bit(PG_property, &((page)->flags))
#define PageProperty(page)			test_bit(PG_property, &((page)->flags))

// convert list entry to page
#define le2page(le, member)					\
	to_struct((le), struct Page, member)

/* free_area_t - maintains a doubly linked list to record free (unused) pages */
typedef struct {
	list_entry_t free_list;			// the list header
	unsigned int nr_free;			// # of free pages in this free list
} free_area_t;

#endif  /* !__ASSEMBLER__ */

#endif  /* !__ARCH_UM_INCLUDE_MEMLAYOUT_H__ */
